package com.obj.commpont.common.utils;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * AES算法加密
 *
 * @author yuan 2018/7/10 17:33
 */
public class AESUtils {

    private static final char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    /**
     * 字符编码
     */
    public static final String UTF_8 = "UTF-8";
    /**
     * 加密算法
     */
    private static final String AES = "AES";

    /**
     * 加密算法/加密模式/填充方式
     */
    private static final String AES_ECB_PKCS5PADDING = "AES/ECB/PKCS5Padding";

    /**
     * 生成密钥长度
     */
    private static final int AES_LENGTH = 128;

    /**
     * 随机生成32位AES密钥
     *
     * @return AES密钥
     */
    public static String getSecretKey() {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
            keyGenerator.init(AES_LENGTH, new SecureRandom());
            SecretKey secretKey = keyGenerator.generateKey();
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getEncoded(), AES);
            return byteToString(secretKeySpec.getEncoded());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 加密数据
     *
     * @param data 待加密数据
     * @param key  加密密钥
     * @return 加密的数据
     */
    public static String encrypt(String data, String key) {
        try {
            return byteToString(encrypt(data.getBytes(UTF_8), key.getBytes(UTF_8)));
        } catch (UnsupportedEncodingException e) {
            return null;
        } catch (NoSuchPaddingException e) {
            return null;
        } catch (NoSuchAlgorithmException e) {
            return null;
        } catch (InvalidKeyException e) {
            return null;
        } catch (IllegalBlockSizeException e) {
            return null;
        } catch (BadPaddingException e) {
            return null;
        }
    }

    /**
     * 解密数据
     *
     * @param data 待加密数据
     * @param key  加密密钥
     * @return 解密的数据
     */
    public static String decrypt(String data, String key) {
        try {
            return new String(decrypt(stringToByte(data), key.getBytes(UTF_8)), UTF_8);
        } catch (UnsupportedEncodingException e) {
            return null;
        } catch (NoSuchPaddingException e) {
            return null;
        } catch (NoSuchAlgorithmException e) {
            return null;
        } catch (InvalidKeyException e) {
            return null;
        } catch (IllegalBlockSizeException e) {
            return null;
        } catch (BadPaddingException e) {
            return null;
        }
    }

    /**
     * 加密数据
     *
     * @param data 待加密数据
     * @param key  加密密钥
     * @return 加密的byte数组
     */
    public static byte[] encrypt(byte[] data, byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
        keyGenerator.init(AES_LENGTH);
        Cipher cipher = Cipher.getInstance(AES_ECB_PKCS5PADDING);
        cipher.init(Cipher.ENCRYPT_MODE, getSecretKey(key));
        return cipher.doFinal(data);
    }


    /**
     * 解密数据
     *
     * @param data 待加密数据
     * @param key  加密密钥
     * @return 解密的byte数组
     */
    public static byte[] decrypt(byte[] data, byte[] key) throws NoSuchAlgorithmException, NoSuchPaddingException,
            InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
        KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
        keyGenerator.init(AES_LENGTH);
        Cipher cipher = Cipher.getInstance(AES_ECB_PKCS5PADDING);
        cipher.init(Cipher.DECRYPT_MODE, getSecretKey(key));
        return cipher.doFinal(data);
    }

    /**
     * byte数组转16进制字符串
     *
     * @param data byte数组
     * @return 字符串
     */
    private static String byteToString(byte[] data) {
        int l = data.length;
        char[] out = new char[l << 1];
        for (int i = 0, j = 0; i < l; i++) {
            out[j++] = hexDigits[(0xF0 & data[i]) >>> 4];
            out[j++] = hexDigits[0x0F & data[i]];
        }
        return new String(out);
    }

    /**
     * 将字符串转化为byte数组
     *
     * @param data 字符串
     * @return byte数组
     */
    private static byte[] stringToByte(String data) {
        char[] chars = data.toCharArray();
        int len = chars.length;

        byte[] out = new byte[len >> 1];
        for (int i = 0, j = 0; j < len; i++) {
            int f = Character.digit(chars[j], 16) << 4;
            j++;
            f = f | Character.digit(chars[j], 16);
            j++;
            out[i] = (byte) (f & 0xFF);
        }
        return out;
    }

    /**
     * 生成AES密钥
     *
     * @param key 解密密钥
     * @return AES密钥
     */
    private static SecretKeySpec getSecretKey(byte[] key) {
        try {
            KeyGenerator keyGenerator = KeyGenerator.getInstance(AES);
            keyGenerator.init(AES_LENGTH);
            return new SecretKeySpec(key, AES);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return null;
        }
    }
}
